package com.gxjtkyy.datadistributer.writer.rdbms.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gxjtkyy.datadistributer.common.exception.ColumnParseException;
import com.gxjtkyy.datadistributer.common.util.DateTimeUtil;
import com.gxjtkyy.datadistributer.writer.rdbms.vo.DbBase;
import com.gxjtkyy.datadistributer.writer.rdbms.vo.DbTableSetting;
import com.gxjtkyy.datadistributer.writer.rdbms.vo.TableMetaData;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
@ConditionalOnProperty(
   value = {"db-writer.type"},
   havingValue = "2"
)
public class DbWriter2Service extends AbstractDbWriterService<Map<String, Map<String, Object>>> {
   private static final Logger log = LoggerFactory.getLogger(DbWriter2Service.class);
   private static final String COLUMN_TYPE_DATE = "DATE";
   private static final String COLUMN_TYPE_TIMESTAMP = "TIMESTAMP";
   private final DbWriterConfigService dbWriterConfigService;
   private final TableMetaDataService tableMetaDataService;
   private final ObjectMapper objectMapper;
   private final DbRecordFilterService dbRecordFilterService;

   public DbWriter2Service(JdbcTemplate jdbcTemplate, ObjectMapper objectMapper, DbWriterConfigService dbWriterConfigService, TableMetaDataService tableMetaDataService, DbRecordFilterService dbRecordFilterService) {
      super(jdbcTemplate);
      this.objectMapper = objectMapper;
      this.dbWriterConfigService = dbWriterConfigService;
      this.tableMetaDataService = tableMetaDataService;
      this.dbRecordFilterService = dbRecordFilterService;
   }

   public DbBase getDbBase(Map<String, Map<String, Object>> dbRecord) {
      try {
         Set<String> tableNames = dbRecord.keySet();
         if (tableNames.size() != 1) {
            throw new ColumnParseException("消息格式异常");
         } else {
            String tableName = (String)tableNames.stream().findFirst().orElseThrow(() -> {
               return new ColumnParseException("消息格式异常");
            });
            DbTableSetting dbTableSetting = this.dbWriterConfigService.getDbTableSetting(tableName);
            DbBase dbBase = new DbBase();
            String targetTableName = dbTableSetting.getTargetTableName();
            dbBase.setTargetTableName(targetTableName);
            dbBase.setInsertable(true);
            dbBase.setUpdatable(dbTableSetting.isUpdatable());
            boolean columnCaseSensitive = dbTableSetting.isColumnCaseSensitive();
            TableMetaData tableMetaData = this.tableMetaDataService.getTableMetaData(targetTableName, columnCaseSensitive);
            if (tableMetaData == null) {
               throw new ColumnParseException("找不到目标表结构");
            } else {
               Map<String, Object> columnValueMap = null;
               if (columnCaseSensitive) {
                  columnValueMap = dbRecord.get(tableName);
               } else {
                  columnValueMap = new HashMap<>(16);
                  Map<String, Object> stringObjectMap = dbRecord.get(tableName);
                  for (String key : stringObjectMap.keySet()) {
                     columnValueMap.put(key.toUpperCase(), stringObjectMap.get(key));
                  }
//                  dbRecord.get(tableName).forEach((key, value) -> {
//                     columnValueMap.put(key.toUpperCase(), value);
//                  });

                  if (((Map)columnValueMap).keySet().size() != ((Map)dbRecord.get(tableName)).keySet().size()) {
                     throw new ColumnParseException("字段数量不一致，请检查大小写敏感配置是否正确");
                  }
               }

//               Stream var10000 = tableMetaData.getAllColumnNames().stream();
//               Objects.requireNonNull(columnValueMap);
//               var10000 = var10000.filter(columnValueMap::containsKey);
               Objects.requireNonNull(dbTableSetting);
               List<String> keyColumnNames = tableMetaData.getAllColumnNames().stream().filter(dbTableSetting::isKeyColumn).collect(Collectors.toList());
               if (!keyColumnNames.isEmpty() && keyColumnNames.size() == dbTableSetting.getKeyColumns().size()) {
//                  var10000 = tableMetaData.getOtherColumnNames().stream();
                  Objects.requireNonNull(columnValueMap);
                  List<String> otherColumnNames = tableMetaData.getAllColumnNames().stream().filter(columnValueMap::containsKey).filter((columnName) -> {
                     return !dbTableSetting.isKeyColumn(columnName);
                  }).filter((columnName) -> {
                     return !dbTableSetting.isIgnoredColumnForInsert(columnName);
                  }).collect(Collectors.toList());
//                  var10000 = tableMetaData.getOtherColumnNames().stream();
                  Objects.requireNonNull(columnValueMap);
                  List<String> updateColumnNames = tableMetaData.getOtherColumnNames().stream().filter(columnValueMap::containsKey).filter((columnName) -> {
                     return !dbTableSetting.isKeyColumn(columnName);
                  }).filter((columnName) -> {
                     return !dbTableSetting.isIgnoredColumnForUpdate(columnName);
                  }).collect(Collectors.toList());
                  List<Object> keyValues = this.getValues(keyColumnNames, (Map)columnValueMap, tableMetaData);
                  List<Object> otherValues = this.getValues(otherColumnNames, (Map)columnValueMap, tableMetaData);
                  List<Object> updateValues = this.getValues(updateColumnNames, (Map)columnValueMap, tableMetaData);
                  dbBase.setKeyColumnNames(keyColumnNames);
                  dbBase.setOtherColumnNames(otherColumnNames);
                  dbBase.setUpdateColumnNames(updateColumnNames);
                  dbBase.setComparableColumns(dbTableSetting.getComparableColumns());
                  dbBase.setKeyValues(keyValues);
                  dbBase.setOtherValues(otherValues);
                  dbBase.setUpdateValues(updateValues);
                  dbBase.setDropWhenValueTooLarge(dbTableSetting.isDropWhenValueTooLarge());
                  dbBase.setDropWhenCannotInsertNull(dbTableSetting.isDropWhenCannotInsertNull());
                  dbBase.setDropWhenValueLargeThanSpecifiedPrecision(dbTableSetting.isDropWhenValueLargeThanSpecifiedPrecision());
                  return dbBase;
               } else {
                  throw new ColumnParseException("消息缺少表主键字段");
               }
            }
         }
      } catch (Exception e) {
         throw new ColumnParseException("消息缺少表主键字段");
      }
   }

   protected boolean isIgnored(Map<String, Map<String, Object>> dbRecord) {
      Iterator var2 = dbRecord.entrySet().iterator();

      while(var2.hasNext()) {
         Entry<String, Map<String, Object>> record = (Entry)var2.next();
         String tableName = (String)record.getKey();
         Map<String, Object> columns = (Map)record.getValue();
         Iterator var6 = columns.entrySet().iterator();

         while(var6.hasNext()) {
            Entry<String, Object> column = (Entry)var6.next();
            String columnName = (String)column.getKey();
            String columnValue = column.getValue().toString();
            if (this.dbRecordFilterService.isIgnoredByColumn(tableName, columnName, columnValue)) {
               return true;
            }
         }
      }

      return false;
   }

   protected Map<String, Map<String, Object>> parseOriginalRecord(String originalRecord)  {
      try {
         return (Map)this.objectMapper.readValue(originalRecord, new TypeReference<Map<String, Map<String, Object>>>() {
         });
      } catch (JsonProcessingException e) {
         // 增加异常日志记录
         log.error("Failed to parse original record: " + originalRecord, e);
         // 可以选择抛出自定义异常或重新抛出原始异常
         throw new RuntimeException("Failed to parse original record", e);
      }
   }

   private List<Object> getValues(List<String> columnNames, Map<String, Object> columnValueMap, TableMetaData tableMetaData) {
      return (List)columnNames.stream().map((columnName) -> {
         Object value = columnValueMap.get(columnName);
         boolean isDateType = value != null && ("DATE".equals(tableMetaData.getColumnTypes().get(columnName)) || "TIMESTAMP".equals(tableMetaData.getColumnTypes().get(columnName)));
         return isDateType ? DateTimeUtil.strToLocalDateTime(value.toString()) : value;
      }).collect(Collectors.toList());
   }
}
